'Imports ccapps.persistent.Telnet

'Namespace persistent.Telnet.Scripting
Namespace persistent.Telnet.Scripting
    Public Class Script

        Public Shared Sub RunScript(ByVal p_host As String, ByVal p_username As String, ByVal p_password As String, ByVal p_commandList() As String)
            Dim l_commandList(p_commandList.Length - 1) As ConditionalCommand
            For index As Integer = 0 To p_commandList.Length - 1
                l_commandList(index) = New ConditionalCommand(p_commandList(index), "/>")
            Next
            RunConditionalScript(p_host, p_username, p_password, l_commandList)
        End Sub

        Public Shared Sub RunConditionalScript(ByVal p_host As String, ByVal p_username As String, ByVal p_password As String, ByVal p_commandList() As ConditionalCommand)
            RunConditionalScript(p_host, p_username, p_password, 6, p_commandList)
        End Sub

        Public Shared Sub RunConditionalScript(ByVal p_host As String, ByVal p_username As String, ByVal p_password As String, ByVal environmentNumber As Integer, ByVal p_commandList() As ConditionalCommand)
            'Dim l_databaseConnection As New OracleClient.OracleConnection(GlobalVar.OraConnStr)
            'Dim l_afterLoginExpect As String = "/>"
            'Dim l_isProductionEnvironment = l_databaseConnection.DataSource = "BSPR"


            'If Not l_isProductionEnvironment Then l_afterLoginExpect = "(1/2/3/4/5/6/7/8/9/10)?"
            'If Not l_isProductionEnvironment Then l_afterLoginExpect = "settings"

            Dim l_request As New ccapps.persistent.Telnet.Scripting.Script(p_host, p_username, p_password)

            'Dim l_oracle_str As String = GlobalVar.OraConnStr
            'l_request.AddLine(New ScriptLine(p_username, "Password"))
            'l_request.AddLine(New ScriptLine(p_password, l_afterLoginExpect))

            'If Not l_isProductionEnvironment Then
            '    l_request.AddLine(New ScriptLine(environmentNumber.ToString(), "/>"))
            'End If

            For commandIndex As Integer = 0 To p_commandList.Length - 1
                If p_commandList(commandIndex).Command.Trim() <> "exit" Then l_request.AddLine(New ScriptLine(p_commandList(commandIndex).Command, p_commandList(commandIndex).ExpectedServerResponseToExecuteNextLine))
            Next

            'l_request.AddLine(New ScriptLine("exit", ""))

            Dim scriptExecuteThread As New System.Threading.Thread(AddressOf l_request.Execute)

            scriptExecuteThread.Start()
            'l_request.Execute()

            Dim waitTimeout As DateTime = DateTime.Now.AddSeconds(120)

            While DateTime.Now < waitTimeout AndAlso (l_request._Result.Status = ScriptExecutionResult.ScriptExecutionStatus.NotStarted OrElse l_request._Result.Status = ScriptExecutionResult.ScriptExecutionStatus.Executing)

            End While

            If scriptExecuteThread.IsAlive Then
                Try
                    scriptExecuteThread.Abort()
                Catch ex As Exception

                Finally

                    If l_request._Result.Status = ScriptExecutionResult.ScriptExecutionStatus.NotStarted OrElse _
                    l_request._Result.Status = ScriptExecutionResult.ScriptExecutionStatus.Executing OrElse _
                    l_request._Result.Status = ScriptExecutionResult.ScriptExecutionStatus.Failed Then
                        Throw New ScriptExecutionException(l_request._Result.Description, Nothing)
                    End If

                End Try
            End If
            'l_request.Execute()

        End Sub

        Private _EntryPoint As ScriptLine
        Private _LastLine As ScriptLine
        Private _ExecutingLine As ScriptLine
        Private _TelnetClient As Tamir.SharpSsh.SshStream
        Public _ResponseBuffer As New ArrayList
        Private _HostName As String
        Private _Result As ScriptExecutionResult

        Public Event ScriptExecutionCompleted(ByVal engine As Script)

        Private Sub RaiseScriptExecutionCompleted(ByVal status As ScriptExecutionResult.ScriptExecutionStatus, ByVal message As String)
            Me._Result = New ScriptExecutionResult(status, String.Empty)
            RaiseEvent ScriptExecutionCompleted(Me)

        End Sub

        Private Sub New(ByVal host As String, ByVal userName As String, ByVal password As String)
            Try
                Me._TelnetClient = New Tamir.SharpSsh.SshStream(host, userName, password)
                Me._Result = New ScriptExecutionResult(ScriptExecutionResult.ScriptExecutionStatus.NotStarted, "Script execution is not started.")
            Catch ex As Exception
                Me.RaiseScriptExecutionCompleted(ScriptExecutionResult.ScriptExecutionStatus.Failed, String.Format("Connection to host '{0}' is failed!", Me._HostName))
            End Try

            Try
                Dim l_databaseConnection As New OracleClient.OracleConnection(GlobalVar.OraConnStr)
                If l_databaseConnection.DataSource = "BSPRD" OrElse l_databaseConnection.DataSource = "BSPR_DEV" Then
                    Me._TelnetClient.Prompt = "(10\)\?\r\n)$"
                Else
                    Me._TelnetClient.Prompt = "(/> )$"
                End If

                Dim response As String = Me._TelnetClient.ReadResponse()
                Me._TelnetClient.Write("6")
                Me._TelnetClient.Prompt = "(/> )$"
                response = Me._TelnetClient.ReadResponse()
            Catch ex As Exception
                Me.RaiseScriptExecutionCompleted(ScriptExecutionResult.ScriptExecutionStatus.Failed, String.Format("Initialization of host '{0}' is failed!", Me._HostName))
            End Try

        End Sub

        'Protected Sub OnServerRespond(ByVal sender As Object, ByVal args As Telnet.ServerResponseEventArgs)
        '    Me._ResponseBuffer.Add(args.Response)
        '    Try
        '        args.Command._Response &= args.Response
        '        args.Command._Responses.Add(args)

        '        'args.IsExpectedResponse = args.Command._Response.IndexOf(args.Command._ResponseProof) > -1
        '        'args.IsExpectedResponse = args.Response.IndexOf(args.Command._ResponseProof) > -1
        '        args.IsExpectedResponse = _
        '                                    args.Command._Response.ToLower().IndexOf(args.Command._ResponseProof.ToLower()) > -1 _
        '                                    OrElse _
        '                                    args.Response.ToLower().IndexOf(args.Command._ResponseProof.ToLower()) > -1
        '        args.Command._Evaluated = args.IsExpectedResponse
        '        Return
        '    Finally
        '        If args.IsExpectedResponse Then args.Command._Signaler.Set()
        '    End Try
        'End Sub

        Public Sub AddLine(ByVal line As ScriptLine)
            If Me._EntryPoint Is Nothing Then
                Me._EntryPoint = line
            Else
                Me._LastLine._NextLine = line
            End If
            Me._LastLine = line
        End Sub

        Public Sub Execute()
            If Me._TelnetClient.CanWrite Then
                Me._Result.Status = ScriptExecutionResult.ScriptExecutionStatus.Executing
                Me._EntryPoint.ExecuteRecursive(Me._TelnetClient, _ExecutingLine)
                Me._TelnetClient.Close()
                If (Me._ExecutingLine Is Me._LastLine AndAlso Me._ExecutingLine._Evaluated) Then
                    Me.RaiseScriptExecutionCompleted(ScriptExecutionResult.ScriptExecutionStatus.Succeed, String.Empty)
                Else
                    Me.RaiseScriptExecutionCompleted(ScriptExecutionResult.ScriptExecutionStatus.Failed, String.Format("No expected response from command '{0}'.", Me._ExecutingLine._Command))
                End If
            Else
                Me.RaiseScriptExecutionCompleted(ScriptExecutionResult.ScriptExecutionStatus.Failed, String.Format("Initialization of host '{0}' is failed!", Me._HostName))
            End If
        End Sub
    End Class

    Public Class ScriptLine
        Public _Command As String
        Public _ResponseProof As String
        Public _Response As String
        Public _Evaluated As Boolean = False
        Public _NextLine As ScriptLine
        Public _Responses As New ArrayList

        Public Sub New(ByVal command As String, ByVal responseProof As String)
            Me._Command = command & Chr(13)
            Me._ResponseProof = responseProof
        End Sub

        Public Sub ExecuteRecursive(ByVal client As Tamir.SharpSsh.SshStream, ByRef executingLine As ScriptLine)
            executingLine = Me
            'If lineIndex = 0 Then
            '    Dim l_databaseConnection As New OracleClient.OracleConnection(GlobalVar.OraConnStr)
            '    If l_databaseConnection.DataSource = "BSPRD" OrElse l_databaseConnection.DataSource = "BSPR_DEV" Then
            '        client.Prompt = "(10\)\?\r\n)$"
            '    End If

            'Else
            '    client.Prompt = ""
            'End If

            client.Prompt = "(/> )$"

            client.Write(Me._Command)

            Dim waitTimeout As DateTime = DateTime.Now.AddSeconds(3)

            While DateTime.Now < waitTimeout : End While

            Dim response As String = client.ReadResponse()

            'System.Web.HttpContext.Current.Response.Write("<br>" & Me._Command & " ---> " & response)

            Me._Evaluated = response.ToLower().IndexOf(Me._ResponseProof.ToLower()) > -1

            If Not Me._Evaluated Then
                Return
            End If

            If Not Me._NextLine Is Nothing Then Me._NextLine.ExecuteRecursive(client, executingLine)
        End Sub
    End Class

    Public Class ConditionalCommand
        Private _Command As String
        Private _ExpectedServerResponseToExecuteNextLine As String

        Public Sub New(ByVal command As String, ByVal expectedServerResponseToExecuteNextLine As String)
            Me._Command = command
            Me._ExpectedServerResponseToExecuteNextLine = expectedServerResponseToExecuteNextLine
        End Sub

        Public ReadOnly Property Command() As String
            Get
                Return Me._Command
            End Get
        End Property

        Public ReadOnly Property ExpectedServerResponseToExecuteNextLine() As String
            Get
                Return Me._ExpectedServerResponseToExecuteNextLine
            End Get
        End Property
    End Class

    Public Class ScriptExecutionResult
        Private _Description As String
        Private _Status As ScriptExecutionStatus

        Public Sub New(ByVal status As ScriptExecutionStatus, ByVal statusDescription As String)
            Me._Status = status
            Me._Description = statusDescription
        End Sub

        Public Property Description() As String
            Get
                Return Me._Description
            End Get
            Set(ByVal Value As String)
                Me._Description = Value
            End Set
        End Property

        Public Property Status() As ScriptExecutionStatus
            Get
                Return Me._Status
            End Get
            Set(ByVal Value As ScriptExecutionStatus)
                Me._Status = Value
            End Set
        End Property

        Public Enum ScriptExecutionStatus
            NotStarted
            Executing
            Failed
            Succeed
        End Enum
    End Class

    Public Class ScriptExecutionException
        Inherits Exception

        Public Sub New(ByVal message As String, ByVal innerException As Exception)
            MyBase.New(hideConnectionAttributes(message), innerException)
        End Sub


        Private Shared Function hideConnectionAttributes(ByVal messageString) As String
            Dim telnetConnectionAttributes As Collections.Specialized.NameValueCollection = persistent.common.GetConnectionAttributesByConfigKey("telnetConnectionString")
            Dim ftpConnectionAttributes As Collections.Specialized.NameValueCollection = persistent.common.GetConnectionAttributesByConfigKey("ftpConnectionString")

            Dim errorMessage As String = messageString
            errorMessage = errorMessage.Replace(telnetConnectionAttributes("UserName"), "[USERNAME]")
            errorMessage = errorMessage.Replace(telnetConnectionAttributes("Password"), "[PASSWORD]")
            errorMessage = errorMessage.Replace(telnetConnectionAttributes("Server"), "[SERVER]")

            errorMessage = errorMessage.Replace(ftpConnectionAttributes("UserName"), "[USERNAME]")
            errorMessage = errorMessage.Replace(ftpConnectionAttributes("Password"), "[PASSWORD]")
            errorMessage = errorMessage.Replace(ftpConnectionAttributes("Server"), "[SERVER]")

            errorMessage = errorMessage.Replace(ConfigurationSettings.AppSettings("UnixOraUsername"), "[USERNAME]")
            errorMessage = errorMessage.Replace(ConfigurationSettings.AppSettings("UnixOraPassword"), "[PASSWORD]")
            errorMessage = errorMessage.Replace(ConfigurationSettings.AppSettings("UnixOraTNS"), "[SERVER]")

            Return errorMessage
        End Function

    End Class

    Public Class TelnetConnectionException
        Inherits Exception

        Public Sub New(ByVal message As String, ByVal innerException As Exception)
            MyBase.New(message, innerException)
        End Sub
    End Class
End Namespace